﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using MetaHeuristics.Collections;

#endregion

namespace MetaHeuristics.Aco.Collections
{
    public sealed class NearestNeighborListMatrix
    {
        private IntMatrix neighbors;

        public NearestNeighborListMatrix(CityDistanceMatrix distances, int depth)
        {
            this.neighbors = new IntMatrix(distances.RowCount, depth);
            this.BuildNeighborLists(distances);
        }

        public int CityCount
        {
            get
            {
                return this.neighbors.RowCount;
            }
        }

        public int Depth
        {
            get
            {
                return this.neighbors.ColumnCount;
            }
        }

        public IntMatrix Neighbors
        {
            get
            {
                return this.neighbors;
            }
        }

        public void BuildNeighborLists(CityDistanceMatrix distances)
        {
            if (distances == null)
                throw new ArgumentNullException("distances");
            if (distances.RowCount != this.CityCount)
                throw new ArgumentNullException("distance city count does not match current city count");

            for (int city = 0; city < this.CityCount; ++city)
            {
                List<City> neighborlist = new List<City>(this.CityCount-1);
                // build the list of distance of the 
                for (int neighbor = 0; neighbor < this.CityCount; ++neighbor)
                {
                    // avoiding self distance
                    if (neighbor == city)
                        continue;

                    // adding distance
                    neighborlist.Add(new City(distances[city,neighbor],neighbor));
                }
                neighborlist.Sort();
                for (int neighbor = 0; neighbor < this.CityCount; ++neighbor)
                {
                    this.neighbors[city,neighbor] = neighborlist[neighbor].Index;
                }
            }
        }

        private class City : IComparable<City>
        {
            public float Distance;
            public int Index;

            public City(float distance, int index)
            {
                this.Distance = distance;
                this.Index = index;
            }

            public bool Equals(City city)
            {
                return this.Distance == city.Distance;
            }

            public int CompareTo(City city)
            {
                return this.Distance.CompareTo(city.Distance);
            }
        }
    }
}
